package cn.good.yan.config.filters;

import com.google.common.collect.Lists;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.net.URI;
import java.util.List;

/**
 * 验证码过滤，只给授权服务配置  （单一过滤器）
 * <p>
 * ValidateCodeGatewayFilterFactory 的配置过滤器，在yml 配置 ValidateCode
 * <p>
 * 该类，是验证验证码的过滤器，可以在网关里实现（生成验证码，校验验证码）逻辑，
 * --- 生产验证码，存在redis中，
 * --- 校验，就是根据验证码，把验证码，去查询Redis有没有，有就通过。
 * --- 但本案例中，验证码逻辑在（授权服务器）里实现
 * <p>
 * <p>
 * 注意：如果配置了（全局过滤器） - 先执行（全局过滤器），然后再执行（单一过滤器）
 *
 * @author shengren.yan
 * @create 2024/11/21
 */
@Component
@Slf4j
public class ValidateCodeGatewayFilterFactory
        extends AbstractGatewayFilterFactory<ValidateCodeGatewayFilterFactory.Config> {

    public ValidateCodeGatewayFilterFactory() {
        super(Config.class);
    }


    // 通过shortcutFieldOrder方法设置Config配置类中的属性,需要根据具体的规则来设置
    // 默认是按照shortcutFieldOrder顺序依次赋值 （这里指的是Config类的属性的名字）
    @Override
    public List<String> shortcutFieldOrder() {

        return Lists.newArrayList("name", "age");
    }

    /**
     * 定义请求过滤器
     *
     * @param config
     * @return {@code GatewayFilter}
     */
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {

            // 逻辑： 非登录/注册请求或验证码关闭，不处理，就是如果是登录、重新登录进行放行

            // 获取请求路径
            String path = exchange.getRequest().getPath().toString();  // 相对路径
            // 全路径的url
            URI uri = exchange.getRequest().getURI();
            System.err.println(String.format("获取到请求路径：%s", uri.toString()));

            // ----------- 案例 -----------
            String name = config.getName();  // 此配置，是得到yml该过滤器后面配置的值 - ValidateCode=abc
            Integer age = config.getAge();   // 如果是多个值，也可以获取 ValidateCode=abc,3  (,分割)
            log.info("从配置文件中获取到的 enabled 的值=[{}].", name);

            if (name.equals("aaa")) {
                return chain.filter(exchange);  // 放行
            }

            if (StringUtils.isNotEmpty(path)) {
                if (path.contains("/login") ||
                        path.contains("/logout") ||
                        path.contains("/capt") ||
                        path.contains("/hello")) {
                    return chain.filter(exchange);  // 放行
                } else {
                    // 返回410，进行拦截
                    exchange.getResponse().setStatusCode(HttpStatus.GONE);
                    return exchange.getResponse().setComplete();
                }
            }
            // 继续执行过滤器链
            return chain.filter(exchange);
        };
    }

    // 配置类，属性用于接收配置文件中的值
    @Data
    public static class Config {
        // 自定义过滤器的参数
        @NotNull
        private String name;
        private Integer age;
    }

    /**
     * # 对应的配置文件， ---- 上面的name的值，是abc
     * # 客户端1
     *  - id: order9003
     *    uri: lb://order9003
     *    predicates:
     *      - Path=/order9003/**
     *    filters:
     *      - StripPrefix=1
     *      - ValidateCode=abc      # 单一过滤器
     *      - ValidateCode=abc,3    # 单一过滤器  (如果有多个参数，配置多个，在Config类添加)
     */


}
